﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharedComponents;

namespace OurLeague.Object
{
    public class LineUp
    {
        #region Fields

        public static int REGULAR = 11;
        public static int RESERVE = 7;

        List<Player> _regularPlayers;
        List<Player> _reservePlayers;
        String _teamId;
        String _lineUpId;

        public static List<LineUp> LineUps = new List<LineUp>();

        #endregion

        #region Constructors

        public LineUp(Team team)
        {
            _teamId = team.Id;
            _regularPlayers = new List<Player>();
            _reservePlayers = new List<Player>();
        }

        public LineUp()
        {
            _regularPlayers = new List<Player>();
            _reservePlayers = new List<Player>();
        }

        #endregion

        #region Public Methods

        public void save()
        {
            MySqlRecord updateRecord = new MySqlRecord();

            updateRecord["fkTeamId"] = TeamId;

            if (!LineUps.Exists(ln => ln.Id == Id))
            {
                LineUps.Add(this);
                Id = MySqlQueryHelper.saveQuery(MySqlManager.Connection, "LineUps", null, updateRecord).ToString();
            }
            else
                MySqlQueryHelper.saveQuery(MySqlManager.Connection, "LineUps", "lineUpId=" + Id, updateRecord);

            updateRecord = new MySqlRecord();
            MySqlQueryHelper.deleteQuery(MySqlManager.Connection, "Lineups_Players", "fkLineUpId=" + Id, null);
            foreach (Player p in RegularPlayers)
            {
                updateRecord["fkLineUpId"] = Id;
                updateRecord["fkPlayerId"] = p.Id;
                updateRecord["onTheBench"] = 0;

                MySqlQueryHelper.saveQuery(MySqlManager.Connection, "Lineups_Players", null, updateRecord);
            }

            foreach (Player p in ReservePlayers)
            {
                updateRecord["fkLineUpId"] = Id;
                updateRecord["fkPlayerId"] = p.Id;
                updateRecord["onTheBench"] = 1;

                MySqlQueryHelper.saveQuery(MySqlManager.Connection, "Lineups_Players", null, updateRecord);
            }
        }

        /// <summary>
        /// Ritorna la lista dinamica dei giocatori in campo
        /// </summary>
        /// <param name="matchId">id della partita</param>
        /// <returns>lista di giocatori in campo</returns>
        public List<Player> regularNow(String matchId)
        {
            List<Player> reg = RegularPlayers.FindAll(p => !p.isSentOff(matchId) && !p.isOut(matchId));
            //List<Player> res = ReservePlayers.FindAll(p => p.isIn(matchId) && !p.isSentOff(matchId));
            //reg.Concat(ReservePlayers.FindAll(p=> p.isIn(matchId) && !p.isSentOff(matchId)));
            foreach (Player pl in ReservePlayers)
                if (pl.isIn(matchId) && !pl.isSentOff(matchId) && !pl.isOut(matchId))
                    reg.Add(pl);
            return reg;
        }

        /// <summary>
        /// Ritorna la lista dinamica dei giocatori in panchina
        /// </summary>
        /// <param name="matchId">id della partita</param>
        /// <returns>lista di giocatori in panchina</returns>
        public List<Player> onTheBenchNow(String matchId)
        {
            /*int ris;
            List<Player> reserve = new List<Player>();
            reserve = ReservePlayers;
            ris = reserve.RemoveAll(p => p.isIn(matchId));
            return reserve;*/
            return ReservePlayers.FindAll(p => !p.isIn(matchId));
        }

        public int remainSubstitutions(String matchId)
        {
            return 3 - ReservePlayers.FindAll(P => P.isIn(matchId)).Count;
        }

        /// <summary>
        /// La lista di tutti i giocatori non in formazione
        /// </summary>
        /// <param name="restrict">se==1 include solo i giocatori disponibili</param>
        /// <returns>Lista dei giocatori</returns>
        public List<Player> notLineUp(int restrict)
        {
            List<Player> pl;
            pl = Player.Players.FindAll(P => P.TeamId == this.TeamId && !this.RegularPlayers.Exists(R => R.Id == P.Id) && !this.ReservePlayers.Exists(R => R.Id == P.Id));
            if (restrict == 1)
                pl = pl.FindAll(P => P.isAvailable());
            return pl;
        }

        /*
        public void delete()
        {
            delete(true);
        }

        public void update(String str)
        {

        }

        public bool findPlayer(String str)
        {

            return false;
        }

        public bool isRegularPlayer(String str)
        {

            return false;
        }
        */
        #endregion

        #region Private Methods

        private void delete(bool check)
        {
            if (check && Match.Matches.Exists(m => this == m.LocalLineUp || this == m.GuestLineUp))
                return;

            MySqlQueryHelper.deleteQuery(MySqlManager.Connection, "LineUps", "lineUpId", new String[] { Id });
            LineUps.Remove(this);
        }

        #endregion

        #region Properties

        public String Id
        {
            get { return _lineUpId; }
            set { _lineUpId = value; }
        }

        public String TeamId
        {
            get { return _teamId; }
            set { _teamId = value; }
        }

        public String TeamName
        {
            get { return (Team.load(TeamId)).Name; }
        }

        public List<Player> RegularPlayers
        {
            get { return _regularPlayers; }
            set { _regularPlayers = value; }
        }

        public List<Player> ReservePlayers
        {
            get { return _reservePlayers; }
            set { _reservePlayers = value; }
        }

        #endregion
        
        #region Static Methods

        public static LineUp load(String idLineUp)
        {
            LineUp lineup = LineUps.Find(r => r._lineUpId == idLineUp);

            if (lineup == null)
            {
                lineup = new LineUp();

                var lineUpRecord = MySqlQueryHelper.selectQuery(MySqlManager.Connection, "LineUps", null, "lineUpId='" + idLineUp + "'")[0];
                var lineUpPlayers = MySqlQueryHelper.selectQuery(MySqlManager.Connection, "LineUps_Players", new String[] { "fkPlayerId", "onTheBench" }, "fkLineUpId='" + idLineUp + "'");

                lineup.Id = idLineUp;
                lineup.TeamId = lineUpRecord["fkTeamId"].ToString();

                foreach (MySqlRecord lineUpPlayerRecord in lineUpPlayers)
                    fillLineUp(lineup, lineUpPlayerRecord);

                LineUps.Add(lineup);
            }

            return lineup;
        }

        public static void removeAll(Match match)
        {
            if (Match.Matches.Contains(match))
                return;

            match.GuestLineUp.delete(false);
            match.LocalLineUp.delete(false);
        }
        
        private static void fillLineUp(LineUp lineup, MySqlRecord lineUpRecord)
        {
            if (!(bool)lineUpRecord["onTheBench"])
                lineup.RegularPlayers.Add(Player.load(lineUpRecord["fkPlayerId"].ToString()));
            else
                lineup.ReservePlayers.Add(Player.load(lineUpRecord["fkPlayerId"].ToString()));
        }

        /// <summary>
        /// Controlla se la formazione rispetta i vincoli
        /// </summary>
        /// <param name="regular">Lista di titolari</param>
        /// <param name="reserve">Lista di riserve</param>
        /// <returns>True se la formazione è corretta, false altrimenti</returns>
        public static bool checkLineUp(List<Player> regular, List<Player> reserve)
        {
            int goalKeeper = 0;

            if (regular.Count() == REGULAR && reserve.Count() == RESERVE)
            {
                foreach (Player p in regular)
                    if (p.Role.ToLower().Trim().Equals("portiere"))
                        goalKeeper++;
                //più di un portiere in campo
                if (goalKeeper != 1)
                    return false;
                goalKeeper = 0;
                foreach (Player p in reserve)
                    if (p.Role.ToLower().Trim().Equals("portiere"))
                        goalKeeper++;
                if (goalKeeper < 1)
                    return false;
                return true;
            }
            return false;
        }
        #endregion
    }
}
